﻿using DDD.Core;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System.Threading;


namespace DDD.EFCore
{
    public class EFContext<TContext> : DbContext, IUnitOfWork
        where TContext : DbContext
    {

        readonly IMediator mediator;
        readonly IPublisherTransactionHandler? publisherTransactionFactory;

        public EFContext(DbContextOptions<TContext> options, IMediator mediator, IServiceProvider provider)
            : base(options)
        {
            //Database.EnsureCreatedAsync().Wait();
            if (Database.GetPendingMigrations().Any())
            {
                var p = provider.GetService<ILoggerProvider>();
                var f = provider.GetService<ILoggerFactory>();
                var logger = p.CreateLogger("数据库迁移");
                logger.LogInformation("***数据库迁移开始");
                foreach (var migration in Database.GetPendingMigrations())
                {
                    logger.LogInformation(migration);
                }
                Database.Migrate();
                logger.LogInformation("***数据库迁移结束");
            }

            this.mediator = mediator;
            this.publisherTransactionFactory = provider.GetService<IPublisherTransactionHandler>();
        }

        public IDbContextTransaction? CurrentTransaction { get; private set; }

        public IDbContextTransaction BeginTransaction()
        {
            if (publisherTransactionFactory != null)
            {
                CurrentTransaction = publisherTransactionFactory.BeginTransaction(this);
            }
            else
            {
                CurrentTransaction = Database.BeginTransaction();
            }

            return CurrentTransaction;
        }

        public async Task CommitAsync(CancellationToken cancellationToken = default)
        {
            if (CurrentTransaction != null)
            {
                await CurrentTransaction.CommitAsync(cancellationToken);
                CurrentTransaction = null;
            }
        }

        public async Task RollbackAsync(CancellationToken cancellationToken = default)
        {
            if (CurrentTransaction != null)
            {
                await CurrentTransaction.RollbackAsync(cancellationToken);
                CurrentTransaction = null;
            }
        }

        public Task<int> SaveChangeAsync(CancellationToken cacellationToken = default)
        {
            return base.SaveChangesAsync(cacellationToken);
        }

        public async Task<bool> SaveUnitOfWorkAsync(CancellationToken cancellationToken = default)
        {
            var eee = this.ChangeTracker.Entries();
          
            await SaveChangesAsync(cancellationToken);
            await mediator.DispatchDomainEventsAsync(this);
            return true;
            // TODO: 这里没想明白 为啥自己开事务？回头再看
            if (CurrentTransaction == null)
            {
                CurrentTransaction = this.BeginTransaction();
                await using (CurrentTransaction)
                {
                    try
                    {
                        await SaveChangesAsync(cancellationToken);
                        await mediator.DispatchDomainEventsAsync(this);
                        await CommitAsync(cancellationToken);
                        return true;
                    }
                    catch
                    {
                        await RollbackAsync(cancellationToken);
                        throw;
                    }
                }
            }
            else
            {
                await SaveChangesAsync(cancellationToken);
                await mediator.DispatchDomainEventsAsync(this);
                return true;
            }
        }
    }

}